package com.study.ioc.demo.instantiationawarebeanpostprocessor;

import com.study.ioc.demo.bean.TestBeanOne;
import com.study.ioc.demo.bean.TestBeanTwo;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;

import java.beans.PropertyDescriptor;

/**
 * @author wuxj
 */
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    /**
     * postProcessBeforeInstantiation方法的作用在目标对象被实例化之前调用的方法，
     * 可以自动生成bean及相关的初始化
     * beanClass参数表示目标对象的类型，beanName是目标实例在Spring容器中的name
     * 如果返回的是null对象，接下来会调用postProcessAfterInstantiation、postProcessPropertyValues、postProcessBeforeInitialization、postProcessAfterInitialization方法
     * 如果返回非null对象，则只执行postProcessAfterInitialization方法
     *
     * @param beanClass
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanClass.getName().equals(TestBeanOne.class.getName())) {
            return null;
        }
        return null;
    }


    /**
     * postProcessAfterInstantiation方法的作用在目标对象被实例化之后并且在属性值被populate之前调用
     * 若返回true则调用postProcessPropertyValues方法
     * 若返回false则不调用postProcessPropertyValues方法
     *
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (bean.getClass().getName().equals(TestBeanOne.class.getName())) {
            return true;
        }
        return false;
    }

    /**
     * postProcessPropertyValues方法的作用在属性中被设置到目标实例之前调用，可以修改属性的设置
     * pvs参数表示参数属性值(从BeanDefinition中获取)，pds代表参数的描述信息(比如参数名，类型等描述信息)，
     * bean参数是目标实例，beanName是目标实例在Spring容器中的name
     * 返回值是PropertyValues，
     * 可以使用一个全新的PropertyValues代替原先的PropertyValues用来覆盖属性设置或者直接在参数pvs上修改。
     * 如果返回值是null，那么会忽略属性设置这个过程(所有属性不论使用什么注解，最后都是null)
     *
     * @param pvs
     * @param pds
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
        if (bean.getClass().getName().equals(TestBeanOne.class.getName())) {
            MutablePropertyValues pvs1 = new MutablePropertyValues();
            pvs1.add("a", "123");
            TestBeanTwo testBeanTwo = new TestBeanTwo();
            //testBeanTwo.setA("123");
            //pvs1.add("testBeanTwo",testBeanTwo);
            return pvs1;
        }
        return pvs;
    }
}
